<?php
/**
 * [ActiveRecord] 模型查询类,构造出操作SQL
 * 
 * @version $Id: Command.php 436 2014-06-10 08:46:21Z wenjingpeng7@gmail.com $
 * @package Mysql
 */
class ArCommand
{
	/**
	 * 数据表替换
	 */
	const AS_TABLE = '`a`';
	
	/**
	 * @var `数据库表名`
	 */
	public $table;
	
	/**
	 * @var 查询条件对象
	 */
	public $oCondition;
	
	/**
	 * 构造函数
	 * 
	 * @param string $table 需要查询的数据库表名
	 * @param ArCondition $oCondition 查询条件对象
	 */
	public function __construct($table, & $oCondition)
	{
		$this->table = $table;
		$this->oCondition = $oCondition;
	}
	
	/**
	 * 插入数据
	 * 
	 * @param array $data 待插入的数据
	 * @param array $fields 字段列表
	 * @param bool $ignore 使用IGNORE参数
	 *
	 * @return string
	 */
	public function insert($data, $fields = array(), $ignore = false)
	{
		$data = $this->_filterData($data, $fields);
		
		///
		$format = "INSERT INTO %s (%s) VALUES (%s)";
		if ($ignore)
			$format = "INSERT IGNORE INTO %s (%s) VALUES (%s)";
		$data = lpString::sqlEscape($data);
		$fields = array_keys($data);
		
		///
		$fields = lpString::dbQuote($fields);
		$query = sprintf($format, 
			$this->table,
			implode(',', $fields),
			implode(',', $data));
		
		///
		return $this->_joinQuery($query, false);
	}
	
	/**
	 * 插入数据
	 * 
	 * @param array $data 待插入的数据
	 * @param array $fields 字段列表
	 * @param array $duplicateFields 需要执行更新字段
	 * @return string
	 */
	public function insertDuplicate($data, $fields = array(), $duplicateFields = array())
	{
		$query = $this->insert($data, $fields);
		
		///
		if (empty($duplicateFields)) 
			$duplicateFields = $fields;
			
		$data = $this->_filterData($data, $duplicateFields);
		
		///
		$format .= " ON DUPLICATE KEY UPDATE %s";
		$data = lpString::sqlEscape($data, true);
		$fields = array_keys($data);
		
		$bits = array();
		foreach ($fields as $f) 
			$bits[] = lpString::dbQuote($f).'='.$data[$f];
			
		///
		$query .= sprintf($format, implode(',', $bits));
		return $query;
	}
	
	/**
	 * 删除数据
	 * 
	 * @return string
	 */
	public function delete()
	{
		$format = "DELETE %s FROM %s AS %s";
		$query = sprintf($format, 
			self::AS_TABLE,
			$this->table,
			self::AS_TABLE);
			
		///
		return $this->_joinQuery($query);
	}
	
	/**
	 * 更新数据
	 * 
	 * @param array $data 待更新的数据
	 * @param array $fields 字段列表
	 * @return string
	 */
	public function update($data, $fields = array())
	{
		$data = $this->_filterData($data, $fields);
		
		///
		$format = "UPDATE %s AS %s SET %s";
		$data = lpString::sqlEscape($data, true);
		$fields = array_keys($data);
		
		///
		$bits = array();
		foreach ($fields as $f) 
			$bits[] = lpString::dbQuote($f).'='.$data[$f];
			
		$query = sprintf($format, 
			$this->table,
			self::AS_TABLE,
			implode(',', $bits));
			
		///
		return $this->_joinQuery($query);
	}
	
	/**
	 * 在某个字段上进行递增或递减操作
	 * 
	 * @param string $field 待更新的字段
	 * @param bool $plus true为递增,false为递减
	 * @param int $step 步长
	 * @return string
	 */
	public function updateStep($field, $plus = true, $step = 1)
	{
		$format = "UPDATE %s AS %s SET %s=%s%s%f";
		$field = lpString::dbQuote($field);
		
		///
		$query = sprintf($format, 
			$this->table,
			self::AS_TABLE,
			$field, $field,
			$plus ? '+' : '-',
			$step);
			
		///
		return $this->_joinQuery($query);
	}
	
	/**
	 * 重新设置操作的数据表名
	 * 
	 * @param string $table 需要查询的数据库表名
	 */
	public function setTable($table)
	{
		$this->table = $table;
	}
	
	
	/// 以下为私有方法 ///
	
	
	/**
	 * 根据字段列表格式化某数据
	 * 
	 * @param array $data 数据源
	 * @param array $fields 字段列表
	 * @return array
	 */
	private function _filterData($data, $fields = array())
	{
		if ( ! empty($fields)) {
			$tmp = array();
			foreach ($fields as $k) {
				if (isset($data[$k])) 
					$tmp[$k] = trim($data[$k]);
			}
			
			$data = $tmp;
		}
		
		return $data;
	}
	
	/**
	 * 操作数据表,执行操作后清空WHERE条件
	 * 
	 * @return string
	 */
	private function _joinQuery($query, $useCondition = true)
	{
		if ( ! empty($useCondition)) 
			$query .= $this->oCondition->__toString();
			
		///
		$this->oCondition->clean();
		return $query;
	}
}
